using System.ComponentModel;
using System.Web;
using System.Security.Permissions;
using System.Web.UI;
using System.Web.UI.WebControls;
using System;

namespace SharpPieces.Web.Controls
{
    /// <summary>
    /// Represents the base class for tag cloud fields.
    /// </summary>
    [TypeConverter(typeof(ExpandableObjectConverter)), DefaultProperty("Visible"), AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal), AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    public abstract class TagCloudField : IStateManager, IDataSourceViewSchemaAccessor
    {

        // Fields

        private bool tracks;
        private DirtyFlags dirtyFlags = DirtyFlags.None;
        private bool visible = true;
        private Style controlStyle;
        private object dataSourceViewSchema = null;

        // Events

        /// <summary>
        /// Occurs when this field has changed.
        /// </summary>
        public event EventHandler FieldChanged;

        // Methods

        /// <summary>
        /// When implemented by a class, loads the server control's previously saved view state to the control.
        /// </summary>
        /// <param name="state">An <see cref="T:System.Object"></see> that contains the saved view state values for the control.</param>
        internal virtual void LoadViewState(object state)
        {
            if (null != state)
            {
                object[] s = state as object[];
                if (null != s[0])
                {
                    this.Visible = (bool)s[0];
                }
                if (null != s[1])
                {
                    ((IStateManager)this.ControlStyle).LoadViewState(s[1]);
                }
            }
        }

        /// <summary>
        /// When implemented by a class, saves the changes to a server control's view state to an <see cref="T:System.Object"></see>.
        /// </summary>
        /// <returns>
        /// The <see cref="T:System.Object"></see> that contains the view state changes.
        /// </returns>
        internal virtual object SaveViewState()
        {
            object[] state = new object[2];

            state[0] = ((this.dirtyFlags & DirtyFlags.Visible) == DirtyFlags.Visible) ? (object)this.Visible : (object)null;
            state[1] = ((this.dirtyFlags & DirtyFlags.ControlStyle) == DirtyFlags.ControlStyle) ? ((IStateManager)this.controlStyle).SaveViewState() : null;

            return state;
        }

        /// <summary>
        /// When implemented by a class, instructs the server control to track changes to its view state.
        /// </summary>
        internal void TrackViewState()
        {
            this.tracks = true;
        }

        /// <summary>
        /// Called when this field has changed.
        /// </summary>
        protected virtual void OnFieldChanged()
        {
            if (null != this.FieldChanged)
            {
                this.FieldChanged(this, EventArgs.Empty);
            }
        }

        /// <summary>
        /// Determines whether the specified <see cref="T:System.Object"></see> is equal to the current <see cref="T:System.Object"></see>.
        /// </summary>
        /// <param name="obj">The <see cref="T:System.Object"></see> to compare with the current <see cref="T:System.Object"></see>.</param>
        /// <returns>
        /// true if the specified <see cref="T:System.Object"></see> is equal to the current <see cref="T:System.Object"></see>; otherwise, false.
        /// </returns>
        public override bool Equals(object obj)
        {
            if ((null == obj) || (typeof(TagCloudField) != obj.GetType()))
            {
                return false;
            }

            TagCloudField field = (TagCloudField)obj;

            return
                (this.Visible == field.Visible) &&
                (this.ControlStyle == field.ControlStyle);
        }

        /// <summary>
        /// Serves as a hash function for a particular type. <see cref="M:System.Object.GetHashCode"></see> is suitable for use in hashing algorithms and data structures like a hash table.
        /// </summary>
        /// <returns>
        /// A hash code for the current <see cref="T:System.Object"></see>.
        /// </returns>
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        // Properties

        /// <summary>
        /// When implemented by a class, gets a value indicating whether a server control is tracking its view state changes.
        /// </summary>
        /// <value></value>
        /// <returns>true if a server control is tracking its view state changes; otherwise, false.</returns>
        internal bool IsTrackingViewState
        {
            get { return this.tracks; }
        }

        /// <summary>
        /// Gets or sets a value indicating whether this <see cref="TagCloudField"/> is visible.
        /// </summary>
        /// <value><c>true</c> if visible; otherwise, <c>false</c>.</value>
        [DefaultValue(true), Description("Gets or sets a value that indicates whether a control is rendered as UI on the page."), Category("Behavior")]
        public bool Visible
        {
            get { return this.visible; }
            set
            {
                if (this.visible != value)
                {
                    this.visible = value;
                    if ((this as IStateManager).IsTrackingViewState)
                    {
                        this.dirtyFlags = this.dirtyFlags | DirtyFlags.Visible;
                    }
                    this.OnFieldChanged();
                }
            }
        }

        /// <summary>
        /// Gets the control style.
        /// </summary>
        /// <value>The control style.</value>
        [PersistenceMode(PersistenceMode.InnerProperty)]
        [Category("Styles"), DefaultValue((string)null), DesignerSerializationVisibility(DesignerSerializationVisibility.Content), Description("The control style.")]
        public Style ControlStyle
        {
            get
            {
                if (this.controlStyle == null)
                {
                    this.controlStyle = new Style();
                    if ((this as IStateManager).IsTrackingViewState)
                    {
                        this.dirtyFlags = this.dirtyFlags | DirtyFlags.ControlStyle;
                    }
                }
                return this.controlStyle;
            }
        }



        // Nested Types

        private enum DirtyFlags
        {
            None = 0,
            Visible = 1,
            ControlStyle = 2,
            All = Visible + ControlStyle
        }

        #region IStateManager Members

        /// <summary>
        /// When implemented by a class, gets a value indicating whether a server control is tracking its view state changes.
        /// </summary>
        /// <value></value>
        /// <returns>true if a server control is tracking its view state changes; otherwise, false.</returns>
        bool IStateManager.IsTrackingViewState
        {
            get { return this.IsTrackingViewState; }
        }

        /// <summary>
        /// When implemented by a class, loads the server control's previously saved view state to the control.
        /// </summary>
        /// <param name="state">An <see cref="T:System.Object"></see> that contains the saved view state values for the control.</param>
        void IStateManager.LoadViewState(object state)
        {
            this.LoadViewState(state);
        }

        /// <summary>
        /// When implemented by a class, saves the changes to a server control's view state to an <see cref="T:System.Object"></see>.
        /// </summary>
        /// <returns>
        /// The <see cref="T:System.Object"></see> that contains the view state changes.
        /// </returns>
        object IStateManager.SaveViewState()
        {
            return this.SaveViewState();
        }

        /// <summary>
        /// When implemented by a class, instructs the server control to track changes to its view state.
        /// </summary>
        void IStateManager.TrackViewState()
        {
            this.TrackViewState();
        }

        #endregion

        #region IDataSourceViewSchemaAccessor Members

        /// <summary>
        /// When implemented, gets or sets the schema associated with the object.
        /// </summary>
        /// <value></value>
        /// <returns>
        /// An <see cref="T:System.Object"/> that represents the schema.
        /// </returns>
        object IDataSourceViewSchemaAccessor.DataSourceViewSchema
        {
            get
            {
                return this.dataSourceViewSchema;
            }
            set
            {
                this.dataSourceViewSchema = value;
            }
        }

        #endregion

    }
}
